home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
tools
/
mg
/
src.lzh
/
amiga
/
rexx.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-23
|
21KB
|
918 lines
/*
* This file sends out and recieves REXX commands (well recieving them means
* we hand the off to excline, but...)
*/
#include "rexx.h"
#ifdef REXX
#include <exec/types.h>
#include <exec/ports.h>
#include <rexx/storage.h>
#include <rexx/rxslib.h>
#ifdef LATTICE
#include <proto/exec.h>
#include <proto/intuition.h>
#else
#include <functions.h>
#endif
#undef TRUE
#undef FALSE
#include "def.h"
#include "line.h"
#include "buffer.h"
#include "window.h"
#include "macro.h"
#include "region.h"
#ifdef ANSI
#undef EOF /* Strange..., but stdio complains about it */
#include <stdio.h> /* Only if we've got sprintf in here */
#include <stdlib.h>
#include <fcntl.h>
#undef HUGE /* Collides with math.h */
#include <math.h>
#include <string.h>
#endif
/*
* The pointer to the Rexx library, which we really want when dealing with
* Rexx, and some return value for messages.
*/
struct Library *RexxSysBase;
#define FAIL_LOCKED 3
#define FAIL_NOREXX 4
/*
* My static functions.
*/
static int rexxdocommand PROTO((char *, long));
static int getrexxargs PROTO((struct RexxMsg *, int));
static int rexxread PROTO((int));
static int rexxstemint PROTO((char *, int, int));
static int rexxstemstring PROTO((char *, int, char *, int));
static int findline PROTO((struct line *));
static struct MsgPort *lockport PROTO((char *));
static int spinport PROTO((struct MsgPort *));
#ifdef LATTICE
long __stdargs SetRexxVar PROTO((struct RexxMsg *, char *, char *, long)) ;
#else
long SetRexxVar PROTO((struct RexxMsg *, char *, char *, long)) ;
static char *strupr PROTO((char *));
#endif
struct RexxArg *CreateArgstring PROTO((char *, long)) ;
long LengthArgstring PROTO((struct RexxArg *)) ;
void DeleteArgstring PROTO((struct RexxArg *)) ;
struct RexxMsg *CreateRexxMsg PROTO((struct MsgPort *, char *, char *)) ;
void ClearRexxMsg PROTO((struct RexxMsg *, long)) ;
void DeleteRexxMsg PROTO((struct RexxMsg *)) ;
/*
* Pointer to rexx macro to run on exit.
*/
static char *RexxExitCmd;
/*
* Commands that return results can only do so if the RexxMsg that caused
* them to be executed is willing to take results. To make this test easy,
* the RexxMsg is stored in CurrentMsg between it's being recieved and
* sending out the reply. Any other time, it will be NULL, and the Rexx
* command check for that if they shouldn't be executed unless there is a
* RexxMsg active. In addition, rexxlock needs to reply to this message
* indicating that the lock succeeded before going into locked mode, so it
* needs access to CurrentMsg. Result strings get passed from rexx commands
* back to the script - and the other way, in the case of rexxdoregion - via
* RexxResult. It's normally NULL, unless the executed command set a result,
* or a macro that we were still locked to on exit returned a result. In
* which case, it points to the RexxArgstring for the result. The consumer is
* responsible for deleting it, and the producer is responsible for creating
* it.
*
*/
static struct RexxMsg *CurrentMsg = NULL;
static struct RexxArg *RexxResult = NULL;
/*
* Things for dealing with asynch REXX messages. rexxport is the port that
* those messages come in on, and it's name is mgname. Since rexxport must be
* checked for messages in the event loop, it's not static. RepliesNeeded is
* the number of reply messages we need to see on rexxport. Lockadd is the
* address of the port name that a given macro is locked to, or NULL if we're
* not locked. ADDSIZE is the size of the port name we use for dynamically
* allocated ports
*/
struct MsgPort *rexxport = NULL;
static char mgname[5] = "mg\0\0";
static unsigned RepliesNeeded = 0;
static char *lockadd = NULL;
#define ADDSIZE 8
/*
* This routine dispatches any REXX messages coming in. However, to allow for
* REXX commands that start other REXX commands, we must save and restore the
* environment (CurrentMsg).
*/
int
disprexx(inport)
struct MsgPort *inport;
{
register int s, t;
register struct RexxMsg *savemsg;
savemsg = CurrentMsg;
for (;;) {
RexxResult = NULL;
/* Check for commands */
if (inport && (CurrentMsg = (struct RexxMsg *) GetMsg(inport))) {
if (CurrentMsg->rm_Node.mn_Node.ln_Type != NT_REPLYMSG)
s = excline(ARG0(CurrentMsg),
LengthArgstring((struct RexxArg *) ARG0(CurrentMsg)));
}
/* And then for replies or asynch commands */
else if (CurrentMsg = (struct RexxMsg *) GetMsg(rexxport)) {
if (CurrentMsg->rm_Node.mn_Node.ln_Type != NT_REPLYMSG)
if (!inport)
s = FAIL_NOREXX;
else if (lockadd)
s = FAIL_LOCKED;
else
s = excline(ARG0(CurrentMsg),
LengthArgstring((struct RexxArg *) ARG0(CurrentMsg)));
}
if (CurrentMsg == NULL)
break;
if (CurrentMsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
RepliesNeeded -= 1;
s = CurrentMsg->rm_Result1 < 2
? 1 - CurrentMsg->rm_Result1
: ABORT;
t = ((char *)CurrentMsg->rm_CommAddr == lockadd);
if (s == TRUE && (CurrentMsg->rm_Action & RXFF_RESULT)
&& CurrentMsg->rm_Result2 != NULL)
/* Aha - a result. Deal with it. */
if (t)
RexxResult = (struct RexxArg *) CurrentMsg->rm_Result2;
else
DeleteArgstring((struct RexxArg *)
CurrentMsg->rm_Result2);
/* Free the memory for this message */
FreeMem(CurrentMsg->rm_CommAddr, ADDSIZE);
ClearRexxMsg(CurrentMsg, 16);
DeleteRexxMsg(CurrentMsg);
if (!t)
continue;
CurrentMsg = savemsg;
lockadd = NULL;
return s;
}
if (s < 2)
s = 1 - s;
CurrentMsg->rm_Result1 = s;
CurrentMsg->rm_Result2 = (RexxResult != NULL)
? (LONG) RexxResult
: 0L;
ReplyMsg((struct Message *) CurrentMsg);
}
CurrentMsg = savemsg;
return -1;
}
void
openrexx()
{
register short i, j;
if ((RexxSysBase = OpenLibrary(RXSNAME, 0)) == NULL)
return;
srand((unsigned) &lockadd); /* Just to make things change */
for (i = 33; i < 127; i++) {
for (j = 33; j < 127; j++) {
Forbid();
if (FindPort(mgname) == NULL)
rexxport = CreatePort(mgname, 0L);
Permit();
if (rexxport != NULL)
return;
mgname[2] = j;
}
mgname[3] = i;
}
/* No port opened, so we don't do Rexx, so we close RexxSysBase */
CloseLibrary(RexxSysBase);
RexxSysBase = NULL;
}
void
closerexx()
{
if (!RexxSysBase)
return; /* No Rexx to close */
if (RexxExitCmd != NULL)
rexxdocommand(RexxExitCmd, RXCOMM);
if (rexxport) {
while (RepliesNeeded) {
WaitPort(rexxport);
disprexx(NULL);
}
DeletePort(rexxport);
}
CloseLibrary(RexxSysBase);
}
/*
* Commands that make Rexx macros execute.
*/
rexxexitcommand(f, n)
{
int s;
static char exitcom[NLINE];
if (!RexxSysBase)
return FALSE;
if ((s = ereply("REXX command to run on exit: ", exitcom, NLINE)) != TRUE)
return s;
RexxExitCmd = exitcom;
return TRUE;
}
rexxcommand(f, n)
{
int s;
char cmd[NLINE];
if (!RexxSysBase)
return FALSE;
if ((s = ereply("REXX command: ", cmd, NLINE)) != TRUE)
return s;
return rexxdocommand(cmd, f & FFUNIV ? RXCOMM | RXFF_TOKEN : RXCOMM);
}
rexxcomregion(f, n)
int f, n;
{
char *out;
register RSIZE length, size;
register struct line *lp;
int status, insertres;
char *string;
struct region reg;
if (!RexxSysBase)
return FALSE;
if ((length = getregion(®)) != TRUE)
return length;
size = reg.r_size;
if ((out = malloc(size + 1)) == NULL) {
ewprintf("Can't get %d bytes", size + 1);
return FALSE;
}
string = out; /* Save the start of the thing... */
/* Copy the region to out */
lp = reg.r_linep;
length = llength(lp) - reg.r_offset;
bcopy(<ext(lp)[reg.r_offset], out, length);
size -= length;
out += length;
while (size > 0) {
/* Add a newline to the output string */
*out++ = '\n';
size -= 1;
/* Add part/all of the current line to the output string */
lp = lforw(lp);
length = llength(lp);
if (length > size)
length = size;
bcopy(ltext(lp), out, length);
out += length;
size -= length;
}
*out = '\0';
/* Figure out how many arguments we really have */
insertres = (n <= 0);
if ((f & FFARG) == 0)
n = 0;
else if (insertres)
n = -n;
if (n > MAXRMARG) {
ewprintf("Can only have %d args for rexx commands", MAXRMARG);
n = MAXRMARG;
}
status = rexxdocommand(string, RXFUNC | RXFF_RESULT | RXFF_STRING | n);
/* Deal with result string if we've got one */
if (status == TRUE && RexxResult != NULL) {
if (insertres)
sinsert((char *) RexxResult);
else
ewprintf("Result was: %s", (char *) RexxResult);
DeleteArgstring(RexxResult);
}
RexxResult = NULL;
return status;
}
/*
* rexxgetargs - get N args from the user, returning ABORT if they abort,
* etc.
*/
int
getrexxargs(msg, n)
struct RexxMsg *msg;
int n;
{
register int count, status = TRUE;
char arg[NLINE];
for (count = 1; count <= n; count += 1) {
if ((status = ereply("Arg #%d? ", arg, NLINE, count)) != TRUE
|| (msg->rm_Args[count] =
(STRPTR) CreateArgstring(arg, strlen(arg))) == NULL)
break;
}
return status;
}
/*
* Finish filling in the msg, send the message to Rexx, and then call
* spinport to get the work done. We get here from commands that can be
* issued by macros, so we can be run when locked. So we have to save lockadd
* upon entry, and restore it before we exit.
*/
static
rexxdocommand(command, action)
char *command;
long action;
{
register struct RexxMsg *out = NULL;
struct MsgPort *macport = NULL, *rexx;
int s;
char *savelock;
if (rexxport == NULL)
return FALSE;
savelock = lockadd;
if ((lockadd = AllocMem(ADDSIZE, 0L)) == NULL) {
ewprintf("Can't get %d bytes", ADDSIZE);
goto error;
}
if ((macport = lockport(lockadd)) == NULL)
goto error;
if ((out = CreateRexxMsg(rexxport, "mg", lockadd)) == NULL
|| (out->rm_Args[0] = (STRPTR) CreateArgstring(command, strlen(command))) == NULL
|| ((action & RXFUNC) && (s = getrexxargs(out, action & 0xF)) != TRUE))
goto error;
out->rm_Action = action;
Forbid();
rexx = FindPort("REXX");
if (rexx)
PutMsg(rexx, (struct Message *) out);
Permit();
if (!rexx) {
s = FALSE;
goto error;
}
RepliesNeeded += 1;
/* Spin until macro finishes, or unlocked */
s = spinport(macport);
lockadd = savelock;
return s;
/* Something died, so clean up and tell the use about it */
error:
if (lockadd)
FreeMem(lockadd, ADDSIZE);
if (macport)
DeletePort(macport);
if (out) {
ClearRexxMsg(out, 16);
DeleteRexxMsg(out);
}
lockadd = savelock;
return s;
}
/*
* Set lockadd to the name of a public port, and return the address of the
* port.
*/
static struct MsgPort *
lockport(portname)
char *portname;
{
struct MsgPort *port = NULL;
while (port == NULL) {
sprintf(portname, "mg_%04d", rand() % 10000);
Forbid();
if (FindPort(portname) == NULL)
port = CreatePort(portname, 0L);
Permit();
}
return port;
}
/*
* Spin on the port we got passed until either rexxunlock is called, or until
* we get a reply message for the macro we started. In the fomer case, return
* true; in the latter, return the value the macro returned.
*/
static int
spinport(port)
struct MsgPort *port;
{
register int s;
register int sigbits;
sigbits = (1l << rexxport->mp_SigBit) | (1L << port->mp_SigBit);
do {
Wait(sigbits);
} while ((s = disprexx(port)) < 0 && lockadd);
DeletePort(port);
if (lockadd)
rexxunlock(FFRAND, 1);
else
s = TRUE;
return s;
}
/*
* rexx locking & unlocking functions. Rexxlock creates a new port for the
* macro we're locking, and calls spinport on that port. Rexxunlock just
* toggles the global lockadd to indicate we're not locked. Both return the
* public port name that will now accept messages to the invoking rexx
* program.
*/
rexxlock(f, n)
int f, n;
{
struct MsgPort *port;
char lockname[ADDSIZE];
/* Make sure we got called properly */
if (!CurrentMsg || lockadd || !(CurrentMsg->rm_Action & RXFF_RESULT))
return FALSE;
if ((port = lockport(lockname)) == NULL)
return FALSE;
CurrentMsg->rm_Result1 = 0;
lockadd = (char *) CreateArgstring(lockname, strlen(lockname));
CurrentMsg->rm_Result2 = (long) lockadd;
ReplyMsg((struct Message *) CurrentMsg);
/* Tun off the reply to this message in disprexx */
CurrentMsg = NULL;
return spinport(port);
}
rexxunlock(f, n)
int f, n;
{
lockadd = NULL;
if (!(f & FFRAND) && CurrentMsg && CurrentMsg->rm_Action & RXFF_RESULT)
RexxResult = CreateArgstring(mgname, strlen(mgname));
return TRUE;
}
/*
* rexx echo line functions.
*/
rexxdisplay(f, n)
int f, n;
{
struct macro *save;
char buf[NLINE];
if (!CurrentMsg)
return FALSE;
eread("", buf, NLINE, 0);
save = inmacro;
inmacro = NULL;
ewprintf("%s", buf);
inmacro = save;
return TRUE;
}
rexxrequest(f, n)
int f, n;
{
return rexxread(EFNEW);
}
rexxreqbuf(f, n)
int f, n;
{
return rexxread(EFNEW | EFBUF);
}
rexxreqfunc(f, n)
int f, n;
{
return rexxread(EFNEW | EFFUNC);
}
rexxreqmacro(f, n)
int f, n;
{
return rexxread(EFNEW | EFMACRO);
}
static
rexxread(flag)
{
char buf[NLINE], inbuf[NLINE];
struct macro *save;
int status;
if (!CurrentMsg)
return FALSE;
eread("", buf, NLINE, 0);
save = inmacro;
inmacro = NULL;
if ((status = eread("%s", inbuf, NLINE, flag, buf)) == TRUE
&& (CurrentMsg->rm_Action & RXFF_RESULT))
RexxResult = CreateArgstring(inbuf, strlen(inbuf));
inmacro = save;
return status;
}
/*
* Misc. rexx functions.
*/
rexxinsert(f, n)
int f, n;
{
KCHAR c;
if (!CurrentMsg)
return FALSE;
c = getkey(SEESCR);
while (c != SOFTCR) {
if (((c == '\n') ? lnewline() : linsert(1, c)) != TRUE)
return FALSE;
c = getkey(SEESCR);
}
return TRUE;
}
rexxline(f, n)
int f, n;
{
register struct line *clp;
if ((CurrentMsg->rm_Action & RXFF_RESULT) == 0)
return TRUE;
if ((f & FFARG) == 0)
clp = curwp->w_dotp;
else if (n > 0) {
clp = lforw(curbp->b_linep); /* "clp" is first line */
while (--n > 0) {
if (lforw(clp) == curbp->b_linep)
return FALSE;
clp = lforw(clp);
}
} else {
clp = lback(curbp->b_linep); /* clp is last line */
while (n < 0) {
if (lback(clp) == curbp->b_linep)
return FALSE;
clp = lback(clp);
n++;
}
}
RexxResult = CreateArgstring(ltext(clp), llength(clp));
return TRUE;
}
/*
* A pair of tools for manipulating the window we use.
*/
rexxwait(f, n)
int f, n;
{
if (!RexxSysBase)
return FALSE;
tthide(FALSE);
WaitPort(rexxport);
ttshow(FALSE);
/* Go run the command and update the screen */
disprexx(rexxport);
update();
return TRUE;
}
rexxtopwindow(f, n)
int f, n;
{
extern struct Window *EmW;
WindowToFront(EmW);
return TRUE;
}
/*
* rexx stem-variable functions.
*/
rexxwindow(f, n)
int f, n;
{
char stem[NLINE];
register int count;
if (!CurrentMsg)
return FALSE;
eread("", stem, NLINE, 0);
/* Upcase the variable name: required by the interface */
strupr(stem);
/* Window Dimensions */
if (rexxstemint(stem, 1, curwp->w_ntrows) == FALSE)
count = 0;
else if (rexxstemint(stem, 2, ncol) == FALSE)
count = 1;
else if (rexxstemint(stem, 3, findline(curwp->w_linep)) == FALSE)
count = 2;
else if (curwp->w_bufp == NULL || curwp->w_bufp->b_bname == NULL
|| rexxstemstring(stem, 4, curwp->w_bufp->b_bname, -1) == FALSE)
count = 3;
else if (rexxstemstring(stem, 5, curwp->w_bufp->b_fname, -1) == FALSE)
count = 4;
else
count = 5; /* Did them ALL! */
rexxstemint(stem, 0, count);
return count == 5;
}
rexxpoint(f, n)
int f, n;
{
char stem[NLINE];
register int count;
if (!CurrentMsg)
return FALSE;
eread("", stem, NLINE, 0);
/* Upcase the variable name: required by the interface */
strupr(stem);
if (rexxstemint(stem, 1, findline(curwp->w_dotp)) == FALSE)
count = 0;
else if (rexxstemint(stem, 2, curwp->w_doto + 1) == FALSE)
count = 1;
else if (rexxstemstring(stem, 3, ltext(curwp->w_dotp), llength(curwp->w_dotp)) == FALSE)
count = 2;
else
count = 3;
rexxstemint(stem, 0, count);
return count == 3;
}
rexxmark(f, n)
int f, n;
{
char stem[NLINE];
register int count;
if (!CurrentMsg)
return FALSE;
eread("", stem, NLINE, 0);
if (curwp->w_markp == NULL) { /* No mark */
rexxstemint(stem, 0, 0);
return FALSE;
}
/* Upcase the variable name: required by the interface */
strupr(stem);
if (rexxstemint(stem, 1, findline(curwp->w_markp)) == FALSE)
count = 0;
else if (rexxstemint(stem, 2, curwp->w_marko + 1) == FALSE)
count = 1;
else if (rexxstemstring(stem, 3, ltext(curwp->w_markp), llength(curwp->w_markp)) == FALSE)
count = 2;
else
count = 3;
rexxstemint(stem, 0, count);
return count == 3;
}
rexxbuffer(f, n)
int f, n;
{
char stem[NLINE];
register int count;
register RSIZE chars, lines;
RSIZE mark, point;
register struct line *clp;
if (!CurrentMsg)
return FALSE;
eread("", stem, NLINE, 0);
/* Upcase the variable name: required by the interface */
strupr(stem);
/* Find the line & dot numbers */
clp = lforw(curbp->b_linep);
mark = point = chars = 0;
for (lines = 1;; lines += 1) {
chars += llength(clp);
if (clp == curwp->w_dotp)
point = lines;
if (clp == curwp->w_markp)
mark = lines;
if ((clp = lforw(clp)) == curbp->b_linep)
break;
chars += 1; /* Newline, if present */
}
if (curbp->b_bname == NULL
|| rexxstemstring(stem, 1, curbp->b_bname, -1) == FALSE)
count = 0;
else if (rexxstemstring(stem, 2, curbp->b_fname, -1) == FALSE)
count = 1;
else if (rexxstemint(stem, 3, lines) == FALSE)
count = 2;
else if (rexxstemint(stem, 4, chars) == FALSE)
count = 3;
else if (rexxstemint(stem, 5, point) == FALSE)
count = 4;
else if (mark == 0 || rexxstemint(stem, 6, mark) == FALSE)
count = 5;
else
count = 6;
rexxstemint(stem, 0, count);
return count == 6;
}
rexxbuflist(f, n)
int f, n;
{
char stem[NLINE], var[NLINE + 10], value[NLINE];
register int count;
register struct buffer *bp;
if (!CurrentMsg)
return FALSE;
eread("", stem, NLINE, 0);
/* Upcase the variable name: required by the interface */
strupr(stem);
for (count = 1, bp = bheadp; bp; bp = bp->b_bufp, count += 1) {
if (bp->b_bname == NULL)
break;
sprintf(var, "%s.%d.NAME", stem, count);
strcpy(value, bp->b_bname);
if (SetRexxVar(CurrentMsg, var, value, strlen(value)))
break;
sprintf(var, "%s.%d.FILE", stem, count);
strcpy(value, bp->b_fname);
if (SetRexxVar(CurrentMsg, var, value, strlen(value)))
break;
sprintf(var, "%s.%d.STATUS", stem, count);
value[0] = '\0';
if (bp->b_flag & BFCHG)
strcat(value, "CHANGED ");
if (bp == curbp)
strcat(value, "CURRENT");
if (SetRexxVar(CurrentMsg, var, value, strlen(value)))
break;
}
rexxstemint(stem, 0, count - 1);
return bp == NULL;
}
rexxregion(f, n)
int f, n;
{
register struct line *lp;
register RSIZE count, length;
char stem[NLINE], out[NLINE + 2];
struct region reg;
if (!CurrentMsg)
return FALSE;
eread("", stem, NLINE, 0);
strupr(stem);
if ((count = getregion(®)) != TRUE) {
rexxstemint(stem, 0, 0);
return count;
}
lp = reg.r_linep;
/* Set up end of first line */
length = llength(lp) - reg.r_offset;
bcopy(<ext(lp)[reg.r_offset], out, length);
count = 1;
while (reg.r_size > length) {
out[length] = '\n';
if (rexxstemstring(stem, count, out, length + 1) == FALSE)
reg.r_size = -1;
else {
reg.r_size -= length + 1;
count += 1;
lp = lforw(lp);
length = llength(lp);
bcopy(ltext(lp), out, length);
}
}
/* Now, if needed, do head of last line */
if (reg.r_size <= 0)
count -= 1;
else if (rexxstemstring(stem, count, out, reg.r_size) == FALSE) {
reg.r_size = -1;
count -= 1;
}
rexxstemint(stem, 0, count);
return reg.r_size != -1;
}
static int
rexxstemint(stem, count, in)
char *stem;
int count, in;
{
char var[NLINE + 2], value[NLINE];
sprintf(var, "%s.%d", stem, count);
sprintf(value, "%d", in);
return SetRexxVar(CurrentMsg, var, value, strlen(value)) == 0;
}
static int
rexxstemstring(stem, count, value, length)
char *stem;
int count;
char *value;
int length;
{
char var[NLINE + 2];
sprintf(var, "%s.%d", stem, count);
if (length < 0)
length = strlen(value);
return SetRexxVar(CurrentMsg, var, value, length) == 0;
}
static int
findline(lp)
struct line *lp;
{
register struct line *slp;
register int count;
for (slp = curbp->b_linep, count = 0;
slp != lp;
slp = lforw(slp), count += 1);
return count;
}
#ifndef LATTICE
static char *
strupr(s)
char *s;
{
char *c;
extern char toupper();
c=s;
while(*s) {
*s = toupper(*s);
s++;
}
return(c);
}
#endif
#else
#include "nullfile.h"
#endif